#!/bin/sh
# ex:sw=4 sts=4
# RedPorts poudriere backend helper
#
# $Id$
#

POUDRIERE=/poudriere
ZFSROOT=zroot
WRKBASE=/tmp/rppoudriere

poudriere_checkout()
{
    TYPE=$1
    REPOSITORY=$2
    REVISION=$3
    BUILD=$4

    PORTSTREE=${POUDRIERE}/ports/${BUILD}

    if [ -z "${BUILD}" ]; then
        echo "Build not specified."
        return 1
    fi

    if [ ! -d ${PORTSTREE} ]; then
        echo "Portstree does not exist."
        return 1
    fi

    if [ "${TYPE}" != "svn" -a "${TYPE}" != "svn-full" -a "${TYPE}" != "git" ]; then
        echo "Unknown repository type"
        return 1
    fi

    LOCK=${WRKBASE}/${BUILD}/.lock

    if [ -f "${LOCK}" ]; then
        echo "Lock ${LOCK} exists."
        return 1
    fi

    if [ ! -d "${WRKBASE}/${BUILD}" ]; then
        mkdir -p ${WRKBASE}/${BUILD} || return 1
    fi

    # create build lock
    touch ${LOCK} || return 1

    # populate lock
    echo "TYPE=\"${TYPE}\"" >> ${LOCK}
    echo "REPOSITORY=\"${REPOSITORY}\"" >> ${LOCK}
    echo "BUILD=\"${BUILD}\"" >> ${LOCK}
    echo "PORTSTREE=\"${PORTSTREE}\"" >> ${LOCK}
    echo "LOCK=\"${LOCK}\"" >> ${LOCK}

    ZFSVOLUME="${ZFSROOT}${PORTSTREE}"
    echo "ZFSVOLUME=\"${ZFSVOLUME}@work\"" >> ${LOCK}

    # Before doing anything, make a snapshot
    zfs snapshot ${ZFSVOLUME}@work || return 3


    # checkout overlay ports
    if [ "${TYPE}" = "svn" ]; then
        PARAMS="--non-interactive"
        if [ -n "${REVISION}" ]; then
            PARAMS="${PARAMS} --revision ${REVISION}"
        fi

        svn checkout ${PARAMS} ${REPOSITORY} ${WRKBASE}/${BUILD}/ports >/dev/null || return 2

        # apply overlay ports
        # Find ports
        find ${WRKBASE}/${BUILD}/ports -type d -d 2 | grep -v ".svn" | grep -v "${WRKBASE}/${BUILDS}/ports/Mk/" | sed -e "s|^${WRKBASE}/${BUILD}/ports/|${PORTSTREE}/|" | xargs rm -Rf || return 1

        cp -pr ${WRKBASE}/${BUILD}/ports/* ${PORTSTREE}/

    elif [ "${TYPE}" = "svn-full" ]; then
        PARAMS="--non-interactive"
        if [ -n "${REVISION}" ]; then
            PARAMS="${PARAMS} --revision ${REVISION}"
        fi

        ln -s ${PORTSTREE} ${WRKBASE}/${BUILD}/ports || return 3

        cd ${TINDERBOX}/portstrees/${PORTSTREE}/ports && svn update ${PARAMS} >/dev/null || return 2

    elif [ "${TYPE}" = "git" ]; then
        git clone ${REPOSITORY}.git ${WRKBASE}/${BUILD}/ports >/dev/null || return 2
        if [ -n "${REVISION}" ]; then
            cd ${WRKBASE}/${BUILD}/ports && git checkout ${REVISION} >/dev/null || return 2
        fi

        # apply overlay ports
        find ${WRKBASE}/${BUILD}/ports -type d -d 2 | grep -v ".git" | grep -v "${WRKBASE}/${BUILDS}/ports/Mk/" | sed -e "s|^${WRKBASE}/${BUILD}/ports/|${PORTSTREE}/|" | xargs rm -Rf || return 1

        cp -pr ${WRKBASE}/${BUILD}/ports/* ${PORTSTREE}/

    fi

    if [ -z "${REVISION}" ]; then
        if [ "${TYPE}" = "git" ]; then
            REVISION=`cd ${WRKBASE}/${BUILD}/ports && git rev-parse HEAD`
        else
            REVISION=`svn info --xml ${PORTSTREE} | xml sel -t -m "/info/entry" -v "@revision"`
        fi
        echo "REVISION=${REVISION}"
    fi

    echo "REVISION=\"${REVISION}\"" >> ${LOCK}
  
    # checkout finished
    touch ${WRKBASE}/${BUILD}/.checkout || return 1

    return 0
}

poudriere_build()
{
    PORT=$1
    BUILD=$2
    PRIORITY=$3
    FINISHURL=$4

    LOCK=${WRKBASE}/${BUILD}/.lock

    if [ ! -f "${LOCK}" ]; then
        echo "No lock for build ${BUILD}"
        return 1
    fi

    . ${LOCK}

    if [ ! -f "${WRKBASE}/${BUILD}/.checkout" ]; then
        echo "No checkout for build ${BUILD}"
        return 1
    fi

    if [ -f "${WRKBASE}/${BUILD}/.build" ]; then
        echo "Build already running"
        return 1
    fi

    if [ -f "${WRKBASE}/${BUILD}/.finished" ]; then
        echo "Build already finished"
        return 1
    fi

    PORTSTREE=${POUDRIERE}/ports/${BUILD}

    if [ ! -d "${PORTSTREE}" ]; then
        echo "Unknown portstree for build ${BUILD}"
        return 1
    fi

    # for svn-full repositories we do not delete packages
    if [ -L "${WRKBASE}/${BUILD}/ports" ]; then
        LASTPACKAGEDATE=""
    else
        LASTPACKAGEDATE=`date "+%Y-%m-%d %H:%M:%S"`
    fi

    echo "PORT=\"${PORT}\"" >> ${LOCK}
    echo "PRIORITY=\"${PRIORITY}\"" >> ${LOCK}
    echo "FINISHURL=\"${FINISHURL}\"" >> ${LOCK}
    echo "LASTPACKAGEDATE=\"${LASTPACKAGEDATE}\"" >> ${LOCK}

    if [ -f "${PORTSTREE}/${PORT}/Makefile" ]; then
        PKGVERSION=`make -C ${PORTSTREE}/${PORT} -V PKGVERSION`
        if [ -n "${PKGVERSION}" ]; then
            echo "PKGVERSION=\"${PKGVERSION}\"" >> ${LOCK}
            echo "PKGVERSION=${PKGVERSION}"
        fi

        # XXX Enqueue to the poudriere redports daemon.
    else
        touch ${WRKBASE}/${BUILD}/.finished
        echo "BUILDSTATUS=\"FAIL\"" >> ${WRKBASE}/${BUILD}/.finished
        echo "FAIL_REASON=\"Port does not exist\"" >> ${WRKBASE}/${BUILD}/.finished
        echo "STATUS=\"finished\"" >> ${WRKBASE}/${BUILD}/.finished
    fi

    touch ${WRKBASE}/${BUILD}/.build || return 1


    return 0
}

poudriere_status()
{
    BUILD=$1
    STATUS="unknown"
    BUILDSTATUS=""

    set -- `poudriere status -H -j ${BUILD} -p ${BUILD} -z 0 -l -f`

    zset=${1}
    tree=${2}
    jail=${3}
    build=${4}
    status=${5}
    queue=${6}
    built=${7}
    fail=${8}
    skip=${9}
    ignore=${10}
    remain=${11}
    time=${12}
    logs=${13}

    case $status in
        "done")
            STATUS="finished" ;;
        "balancing_pool"|"build_port_done"|"building"|"clean_pool"|"clean_restricted"|"cleaning"|"committing"|"computingdeps"|"computingrdeps"|"index"|"loading_moved"|"parallel_build"|"pkgrepo"|"sanity"|"starting_builders"|"starting_jobs"|"stopping_jobs"|"updating_stats"|"stage-qa"|"check-plist"|"leftovers")
            STATUS="building" ;;
        "idle")
            STATUS="idle"
            PORTSTREE=${POUDRIERE}/ports/${BUILD}
            # XXX
            PORTSTREELASTBUILT=some timestamp I have to figure out the format of

            echo "PORTSTREELASTBUILT=${PORTSTREELASTBUILT}"
            ;;
        *)
            STATUS="finished"
            BUILDSTATUS=$status
            ;;
    esac

    if [ -f "${WRKBASE}/${BUILD}/.finished" ]; then
        . ${WRKBASE}/${BUILD}/.finished

        if [ -n "${FAIL_REASON}" ]; then
            echo "FAIL_REASON=${FAIL_REASON}"
        fi

        if [ -n "${BUILDLOG}" ]; then
            echo "BUILDLOG=${BUILDLOG}"
        fi

        if [ -n "${WRKDIR}" ]; then
            echo "WRKDIR=${WRKDIR}"
        fi
    fi

    echo "STATUS=${STATUS}"

    if [ -n "${BUILDSTATUS}" ]; then
        echo "BUILDSTATUS=${BUILDSTATUS}"
    fi

    return 0
}

poudriere_clean()
{
    BUILD=$1
    LOCK=${WRKBASE}/${BUILD}/.lock
    PORTSTREE=${POUDRIERE}/ports/${BUILD}

    zfs rollback ${ZFSROOT}${PORTSTREE}@clean

    . ${LOCK}

    # Remove packages that have been built during the run and may be
    # customized.
    if [ -f "${WRKBASE}/${BUILD}/.build" -a -n "${LASTPACKAGEDATE}" ]; then
        find ${POUDRIERE}/data/packages/${BUILD}-${BUILD}/All -type f -newermt "${LASTPACKAGEDATE}" -delete
    fi

    # There possibly is more cleanup to do here.
    # Also, this "more" may be needed in recover after.

    return 0
}

poudriere_update()
{
    BUILD=$1

    PORTSTREE=${POUDRIERE}/ports/${BUILD}

    if [ ! -d "${PORTSTREE}" ]; then
        echo "Unknown portstree for build ${BUILD}"
        return 1
    fi

    zfs rollback ${ZFSROOT}${PORTSTREE}@clean

    if svn update -q ${PORTSTREE}
    then
        zfs snapshot ${ZFSROOT}${PORTSTREE}@clean2
        zfs destroy ${ZFSROOT}${PORTSTREE}@clean
        zfs rename ${ZFSROOT}${PORTSTREE}@clean2 ${ZFSROOT}${PORTSTREE}@clean
    else
        zfs rollback ${ZFSROOT}${PORTSTREE}@clean
        echo "svn update failed for ${PORTSTREE}"
        return 1
    fi

    return 0
}

poudriere_recover()
{
    BUILD=$1
    PORTSTREE=${POUDRIERE}/ports/${BUILD}

    zfs rollback ${ZFSROOT}${PORTSTREE}@clean

    # There is possibly more cleanup to do here.
    # Also, this "more" may be needed in clean before.

    return 0
}

poudriere_selftest()
{
    BUILD=$1

    if [ ! -d "${POUDRIERE}/jails/${BUILD}" ]; then
        echo "Unknown build ${BUILD}"
        return 1
    fi

    if [ -z "${POUDRIERE}/ports/${BUILD}" ]; then
        echo "Unknown portstree for build ${BUILD}"
        return 1
    fi

    return 0
}


